/*******************************************************************************
 * Witz - Winboard Chess Engine                                                *
 * EVAL.C                                                                      *
 *                                                                             *
 * The evaluvation functi for Witz                                             *
 *                                                                             *
 * Please refer to the licence notice in MAIN.C                                *
 *                                                                             *
 * Copywright (C) 2006 Pradu Kannan                                            *
 * http://witz.sf.net/                                                         *
 ******************************************************************************/

#include "build.h"
#include "defs.h"
#include "protos.h"
#include "data.h"
#include "debug.h"

//Piece Value Array
int PieceVal[7];

//piece values
int Pval;	//pawn value
int Nval;	//knight value
int Bval;	//bishop value
int Rval;	//rook value
int Qval;	//queen value
int Kval;	//king value

//mobility weights
int MOB_WEIGHT;
int CAPTURE_BONUS;
int KS_WEIGHT;

float KS_SUM;
int KS_ScaleStart;
int KS_ScaleEnd;

//Passed Pawn Piece Square Table for initial position
int passedPawnPST[64];
int default_passedPawnPST[64] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	20, 19, 18, 17, 17, 18, 19, 20,
	27, 26, 24, 23, 23, 24, 26, 27,
	36, 35, 33, 31, 31, 33, 35, 36,
	49, 47, 44, 42, 42, 44, 47, 49,
	66, 63, 60, 56, 56, 60, 63, 66,
	90, 85, 81, 76, 76, 81, 85, 90,
	 0,  0,  0,  0,  0,  0,  0,  0
};

//Half-Passed Pawn Piece Square Table for initial position
int halfpassedPawnPST[64];
int default_halfpassedPawnPST[64] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	 6,  6,  5,  5,  5,  5,  6,  6,
	 8,  8,  7,  7,  7,  7,  8,  8,
	11, 10, 10,  9,  9, 10, 10, 11,
	15, 14, 13, 12, 12, 13, 14, 15,
	20, 19, 17, 16, 16, 17, 19, 20,
	27, 25, 24, 22, 22, 24, 25, 27,
	 0,  0,  0,  0,  0,  0,  0,  0
};

//Doubled Pawn Piece Square Table for initial position
int doubledPawnPST[64];
int default_doubledPawnPST[64] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 0,  0,  0,  0,  0,  0,  0,  0
};

//Isolated Pawn Piece Square Table for initial position
int isolatedPawnPST[64];
int default_isolatedPawnPST[64] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 6,  6,  6,  6,  6,  6,  6,  6,
	 0,  0,  0,  0,  0,  0,  0,  0
};

//not-Defendable Pawn Piece Square Table for initial position
int notDefendablePawnPST[64];
int default_notDefendablePawnPST[64] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 2,  2,  2,  2,  2,  2,  2,  2,
	 0,  0,  0,  0,  0,  0,  0,  0
};

/*printEval()
 *prints all the elements in the eval
 *used mainly for debugging purposes
 */
void printEval(const board* pos)
{
	U64 pawnAttacks[2], diagAttacks[2], rookAttacks[2], knightAttacks[2];
	int pieceMaterial[2];
	pieceMaterial[pos->side]=Nval*popCount(piecesSide(*pos,N))+Bval*popCount(piecesSide(*pos,B))
		+Rval*popCount(piecesSide(*pos,R))+Qval*popCount(piecesSide(*pos,Q));
	pieceMaterial[pos->xside]=Nval*popCount(piecesXSide(*pos,N))+Bval*popCount(piecesXSide(*pos,B))
		+Rval*popCount(piecesXSide(*pos,R))+Qval*popCount(piecesXSide(*pos,Q));
	printf("QSearch Score  : %d\n",ABhorizonScore(NEGINF, INF, pos));
	printf("Eval Score     : %d\n",eval(pos));
	printf("\tMaterial       : %d\n",signSide[pos->side]*(pos->material));
	printf("\tMobility Score : %d\n",mobility(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks));
	printf("\tKing Safety    : %d\n",kingsafety(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks,pieceMaterial));
	
	printf("\tPawn Structure : %d\n",pawnEval(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks));
	//printf("\t\tPassed Pawn    : %d\n",passedPawnEval(pos));
}

/*eval()
 *evaluvates a position
 *
 *@param pos - the board position to be evaluvated
 *@returns the score of the position with respect to the side to play
 */
int eval(const board* pos)
{
	int score,pieceMaterial[2];
	U64 pawnAttacks[2],diagAttacks[2], rookAttacks[2], knightAttacks[2];

	//material (the value each piece can be found in defs.h)
	score=signSide[pos->side]*(pos->material);
	//mobility (the difference between the number of moves playable on each side)
	pieceMaterial[pos->side]=Nval*popCount(piecesSide(*pos,N))+Bval*popCount(piecesSide(*pos,B))
		+Rval*popCount(piecesSide(*pos,R))+Qval*popCount(piecesSide(*pos,Q));
	pieceMaterial[pos->xside]=Nval*popCount(piecesXSide(*pos,N))+Bval*popCount(piecesXSide(*pos,B))
		+Rval*popCount(piecesXSide(*pos,R))+Qval*popCount(piecesXSide(*pos,Q));
	score+=mobility(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks);
	//king "safety" (the difference between the number of potential king attackers)
	score+=kingsafety(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks,pieceMaterial);
	score+=pawnEval(pos,pawnAttacks,diagAttacks,rookAttacks,knightAttacks);
	return score;
}

/*mobility()
 *counts the number of safe moves (excluding castling) each side can make
 *for pawns it only counts the single square ahead of it
 *It also generates information about attacks from both the opponent and current sides
 *@param pos - the board position to be evaluvated
 *@param diagAttacks - a pointer to an array (size 2) of diagonal attacks for each side
 *@param rookAttacks - a pointer to an array (size 2) of horizontal and vertical attacks for each side
 *@param knightAttacks - a pointer to an array (size 2) of knight attacks for each side
 *@returns the difference in the number of moves each side can make with respect to the side to play
 */
int mobility(const board* pos, U64* pawnAttacks, U64* diagAttacks, U64* rookAttacks, U64* knightAttacks)
{
	U64 pieceboard, temp, temp2;
	int index, mob=0;
	U64 safeSquares[2]={U64FULL,U64FULL};
	pawnAttacks[BLACK]=diagAttacks[BLACK]=rookAttacks[BLACK]=knightAttacks[BLACK]=U64EMPTY;
	pawnAttacks[WHITE]=diagAttacks[WHITE]=rookAttacks[WHITE]=knightAttacks[WHITE]=U64EMPTY;

	//Pawn mobility
	
	mob+=popCount((piecesWHITE(*pos,P)<<8)&~pos->AllPieces);
	mob-=popCount((piecesBLACK(*pos,P)>>8)&~pos->AllPieces);
	

	//Pawn Attacks
	pieceboard=piecesBLACK(*pos,P);
	pawnAttacks[BLACK]=((pieceboard&0x7F7F7F7F7F7F7F7FULL)>>7)|((pieceboard&0xFEFEFEFEFEFEFEFEULL)>>9);
	pieceboard=piecesWHITE(*pos,P);
	pawnAttacks[WHITE]=((pieceboard&0x7F7F7F7F7F7F7F7FULL)<<9)|((pieceboard&0xFEFEFEFEFEFEFEFEULL)<<7);

	//Pawn attacks are now concidered unsafe
	safeSquares[WHITE]&=~pawnAttacks[BLACK];
	safeSquares[BLACK]&=~pawnAttacks[WHITE];

	//Knight Mobility
	pieceboard=piecesWHITE(*pos,N);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		knightAttacks[WHITE]|=temp=Nmoves(*pos,index);
		mob+=popCount(temp&safeSquares[WHITE]);
		pieceboard^=toBit[index];
	}
	pieceboard=piecesBLACK(*pos,N);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		knightAttacks[BLACK]|=temp=Nmoves(*pos,index);
		mob-=popCount(temp&safeSquares[BLACK]);
		pieceboard^=toBit[index];
	}

	//Bishop Mobility
	pieceboard=piecesWHITE(*pos,B);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		diagAttacks[WHITE]|=temp=Bmoves(*pos,index);
		mob+=popCount(temp&safeSquares[WHITE]);
		pieceboard^=toBit[index];
	}
	pieceboard=piecesBLACK(*pos,B);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		diagAttacks[BLACK]|=temp=Bmoves(*pos,index);
		mob-=popCount(temp&safeSquares[BLACK]);
		pieceboard^=toBit[index];
	}

	//Bishop and Knight attacks are now concidered unsafe
	safeSquares[WHITE]&=~knightAttacks[BLACK];
	safeSquares[BLACK]&=~knightAttacks[WHITE];
	safeSquares[WHITE]&=~diagAttacks[BLACK];
	safeSquares[BLACK]&=~diagAttacks[WHITE];

	//Rook Mobility
	pieceboard=piecesWHITE(*pos,R);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		rookAttacks[WHITE]|=temp=Rmoves(*pos,index);
		mob+=popCount(temp&safeSquares[WHITE]);
		pieceboard^=toBit[index];
	}
	pieceboard=piecesBLACK(*pos,R);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		rookAttacks[BLACK]|=temp=Rmoves(*pos,index);
		mob-=popCount(temp&safeSquares[BLACK]);
		pieceboard^=toBit[index];
	}

	//Rook attacks are now unsafe
	safeSquares[WHITE]&=~rookAttacks[BLACK];
	safeSquares[BLACK]&=~rookAttacks[WHITE];

	//Queen Mobility
	pieceboard=piecesWHITE(*pos,Q);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		diagAttacks[WHITE]|=temp=Bmoves(*pos,index);
		rookAttacks[WHITE]|=temp2=Rmoves(*pos,index);
		mob+=popCount((temp|temp2)&safeSquares[WHITE]);
		pieceboard^=toBit[index];
	}
	pieceboard=piecesBLACK(*pos,Q);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		diagAttacks[BLACK]|=temp=Bmoves(*pos,index);
		rookAttacks[BLACK]|=temp2=Rmoves(*pos,index);
		mob-=popCount((temp|temp2)&safeSquares[BLACK]);
		pieceboard^=toBit[index];
	}

	//King Mobility
	/*pieceboard=piecesWHITE(*pos,K);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		mob+=popCount(Kmoves(*pos,index));
		pieceboard^=toBit[index];
	}

	//Other side's mobility
	pieceboard=piecesBLACK(*pos,K);
	while(pieceboard)
	{
		index=LastOne(pieceboard);
		mob-=popCount(Kmoves(*pos,index));
		pieceboard^=toBit[index];
	}*/

	mob*=MOB_WEIGHT*signSide[pos->side];

	//give bonus for captures
	mob+=CAPTURE_BONUS*popCount(diagAttacks[pos->side]&pos->PiecesSide[pos->xside]);
	mob+=CAPTURE_BONUS*popCount(rookAttacks[pos->side]&pos->PiecesSide[pos->xside]);
	mob+=CAPTURE_BONUS*popCount(knightAttacks[pos->side]&pos->PiecesSide[pos->xside]);

	mob-=CAPTURE_BONUS*popCount(diagAttacks[pos->xside]&pos->PiecesSide[pos->side]);
	mob-=CAPTURE_BONUS*popCount(rookAttacks[pos->xside]&pos->PiecesSide[pos->side]);
	mob-=CAPTURE_BONUS*popCount(knightAttacks[pos->xside]&pos->PiecesSide[pos->side]);


	return mob;
}

/*kingsafety()
 *A highly dynamic king-safety evaluvation
 *How it works:
 *1)It generates all the bishop moves for each square around the king and &s it with
 *all the diagonal attacks that can be done by the opposing side
 *2)It generates all the rook moves for each square around the king and &s it with
 *all the horizontal and vertical attacks that can be done by the opposing side
 *3)It generates all the knight moves for each square around the king and &s it with
 *all the knight moves to that square
 *4)It repeates the above three steps for the square the king itself is on which doubles
 *any attacks directed directly towards the king
 *The reason why this is so dyamic is that the function needs no adjustion between opening,
 *middle game and endgame.  It evaluvates the kingsafety accurately for all stages of the game.
 *
 *@param pos - the board position to be evaluvated
 *@param diagAttacks - a pointer to an array (size 2) of diagonal attacks for each side
 *@param rookAttacks - a pointer to an array (size 2) of horizontal and vertical attacks for each side
 *@param knightAttacks - a pointer to an array (size 2) of knight attacks for each side
 *
 *@returns the difference in the number of potential attakers to each side's king
 */
int kingsafety(const board* pos, const U64* pawnAttacks, const U64* diagAttacks, const U64* rookAttacks, const U64* knightAttacks, const int* pieceMaterial)
{
	U64 squares;     //the squares around the king and the square the king is on
	int scoreWHITE=0, scoreBLACK=0, target;
	char kingpos;

	//King safety for white
	if(pieceMaterial[BLACK]>KS_ScaleEnd)
	{
		kingpos=LastOne(piecesWHITE(*pos,K));
		squares=Kmoves(*pos,kingpos)|toBit[kingpos];
		while(squares)
		{
			target=LastOne(squares);
			scoreWHITE-=popCount(diagAttacks[BLACK]&Bmoves(*pos,target));
			scoreWHITE-=popCount(rookAttacks[BLACK]&Rmoves(*pos,target));
			scoreWHITE-=popCount(knightAttacks[BLACK]&Nmoves(*pos,target));
			squares^=toBit[target];
		}
		scoreWHITE*=KS_WEIGHT;
		if(pieceMaterial[BLACK]<KS_ScaleStart)
			scoreWHITE=(int)(scoreWHITE*((pieceMaterial[BLACK]-KS_ScaleEnd)/KS_SUM));
	}

	//King safety for black
	if(pieceMaterial[WHITE]>KS_ScaleEnd)
	{
		kingpos=LastOne(piecesBLACK(*pos,K));
		squares=Kmoves(*pos,kingpos)|toBit[kingpos];
		while(squares)
		{
			target=LastOne(squares);
			scoreBLACK+=popCount(diagAttacks[WHITE]&Bmoves(*pos,target));
			scoreBLACK+=popCount(rookAttacks[WHITE]&Rmoves(*pos,target));
			scoreBLACK+=popCount(knightAttacks[WHITE]&Nmoves(*pos,target));
			squares^=toBit[target];
		}
		scoreBLACK*=KS_WEIGHT;
		if(pieceMaterial[WHITE]<KS_ScaleStart)
			scoreBLACK=(int)(scoreBLACK*((pieceMaterial[WHITE]-KS_ScaleEnd)/KS_SUM));
	}
	return (scoreWHITE+scoreBLACK)*signSide[pos->side];
}

/*pawnEval()
 *pawn structure evaluvation
 *
 *@param pos - the board position to be evaluvated
 *
 *@returns a pawn structure evaluvation
 */
int pawnEval(const board* pos, const U64* pawnAttacks, const U64* diagAttacks, const U64* rookAttacks, const U64* knightAttacks)
{
	int sq, score=0;
	U64 WhitePawns = piecesWHITE(*pos,P);
	U64 BlackPawns = piecesBLACK(*pos,P);

	U64 doubledWHITE=WhitePawns & fillDown(WhitePawns);
	U64 doubledBLACK=BlackPawns & fillUp(BlackPawns);

	U64 passedWHITE=WhitePawns & ~doubledWHITE & ~fillDown2(BlackPawns|pawnAttacks[BLACK]);
	U64 passedBLACK=BlackPawns & ~doubledBLACK & ~fillUp2(WhitePawns|pawnAttacks[WHITE]);

	U64 notDefendableWHITE=WhitePawns&~fillUp2(pawnAttacks[WHITE]>>8);
	U64 notDefendableBLACK=BlackPawns&~fillDown2(pawnAttacks[BLACK]<<8);

	U64 isolatedWHITE=notDefendableWHITE&~fillDown(((WhitePawns&0xFEFEFEFEFEFEFEFEULL)<<1)|((WhitePawns&0x7F7F7F7F7F7F7F7FULL)>>1));
	U64 isolatedBLACK=notDefendableBLACK&~fillUp(((BlackPawns&0xFEFEFEFEFEFEFEFEULL)<<1)|((BlackPawns&0x7F7F7F7F7F7F7F7FULL)>>1));

	U64 halfpassedWHITE=~notDefendableWHITE&(~passedWHITE)&(
		(WhitePawns & ~fillDown2(BlackPawns|((BlackPawns&0x7F7F7F7F7F7F7F7FULL)>>7)))|
		(WhitePawns & ~fillDown2(BlackPawns|((BlackPawns&0xFEFEFEFEFEFEFEFEULL)>>9))));
	U64 halfpassedBLACK=~notDefendableBLACK&(~passedBLACK)&(
		(BlackPawns & ~fillUp2(WhitePawns|((WhitePawns&0x7F7F7F7F7F7F7F7FULL)<<9)))|
		(BlackPawns & ~fillUp2(WhitePawns|((WhitePawns&0xFEFEFEFEFEFEFEFEULL)<<7))));

	//Doubled pawns

	while(doubledWHITE)
	{
		sq=LastOne(doubledWHITE);
		score+=doubledPawnPST[sq];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		doubledWHITE^=toBit[sq];
	}
	while(doubledBLACK)
	{
		sq=LastOne(doubledBLACK);
		score-=doubledPawnPST[flip[sq]];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		doubledBLACK^=toBit[sq];
	}

	//Passed pawns

	while(passedWHITE)
	{
		sq=LastOne(passedWHITE);
		score+=passedPawnPST[sq];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		passedWHITE^=toBit[sq];
	}
	while(passedBLACK)
	{
		sq=LastOne(passedBLACK);
		score-=passedPawnPST[flip[sq]];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		passedBLACK^=toBit[sq];
	}

	//not defendable pawns

	while(notDefendableWHITE)
	{
		sq=LastOne(notDefendableWHITE);
		score+=notDefendablePawnPST[sq];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		notDefendableWHITE^=toBit[sq];
	}
	while(notDefendableBLACK)
	{
		sq=LastOne(notDefendableBLACK);
		score-=notDefendablePawnPST[flip[sq]];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		notDefendableBLACK^=toBit[sq];
	}

	//isolated pawns

	while(isolatedWHITE)
	{
		sq=LastOne(isolatedWHITE);
		score+=isolatedPawnPST[sq];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		isolatedWHITE^=toBit[sq];
	}
	while(isolatedBLACK)
	{
		sq=LastOne(isolatedBLACK);
		score-=isolatedPawnPST[flip[sq]];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		isolatedBLACK^=toBit[sq];
	}

	//half-passed pawns that are defendable

	while(halfpassedWHITE)
	{
		sq=LastOne(halfpassedWHITE);
		score+=halfpassedPawnPST[sq];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		halfpassedWHITE^=toBit[sq];
	}
	while(halfpassedBLACK)
	{
		sq=LastOne(halfpassedBLACK);
		score-=halfpassedPawnPST[flip[sq]];
		//Bonus for enemy king too far
		//Bonus for our king close to it
		halfpassedBLACK^=toBit[sq];
	}

	return signSide[pos->side]*score;
}


/*decidable()
 *determine's if the game's outcome can be predicted
 *
 *@param pos       - the board position
 *@param drawTable - the 3-move repetetion draw table
 *@param dfr       - depth from root3
 *@param result    - stores the result if the game is decidable
 *                   otherwise leaves this parameter alone
 *
 *@returns true if the position's result can be predicted
 */
bool decidable(const board* pos, const drawEntry* drawTable, const short dfr, int* result)
{
	short i;
	if(pos->fifty>=100) //fifty move
	{
		*result=0;
		return true;
	}

	//3 fold repetetion
	if(drawTable!=NULL)
	{
		//in search tree
		for(i=dfr-1;i>=0;i--)
		{
			if(drawTable[i].hashkey==pos->hashkey)
			{
				*result=0;
				return true;
			}
			if(drawTable[i].fiftyReset)
				return false; //FIX TIHS
		}

		//in game tree
		for(i=gamedepth-1;i>=gamedepth-mainboard.fifty;i--)
		{
			if(gameHistory[i].hashkey==pos->hashkey)
				{
					*result=0;
					return true;
				}
		}
	}
	return false;
}

/*

openPawns[WHITE] = pawnBB[WHITE] & ~filldown(allPawns);
passedPawns[WHITE] = pawnBB[WHITE] & ~filldown(allPawns|pawnAttacks[BLACK]);
notDefendable[WHITE] = pawnBB[WHITE] & fillup(pawnAttacks[WHITE]);

OpenPawns: All pawns without own or opposite pawns infront on same file.

Backward pawns:

First we need all squares dominated by sides pawn attacks:

pawnDomination[side] = (pawnDblAttacks[side] & ~pawnDblAttacks[other(side)])
| (pawnAttacks[side] & ~pawnAttacks[other(side)]);

backWard1[WHITE] = notDefendable[WHITE] & (pawnDomination[BLACK] >> 8);
backWard2[WHITE] = backWard1[WHITE] & openPawns[WHITE];
*/
